﻿using System;
using System.Collections.Generic;
using System.Linq;
using MvcEngine.Mvc.StarterSite.Controllers;
using System.Web.Mvc;
using MvcEngine.Mvc.Models.ViewModels;
using MvcEngine.Blog.Models.Entities;
using MvcEngine.Blog.Components.Extensions;
using MvcEngine.Blog.Models.ViewData;
using MvcEngine.Core;
using MvcEngine.Mvc.Extensions;
using MvcEngine.Blog.Repositories;
using MvcEngine.Core.Repositories;
using MvcEngine.Core.Helpers;
using MvcEngine.Blog.Helper;
using System.Web;
using MvcEngine.Mvc.Filters;
using MvcEngine.Core.Exceptions;
using MvcEngine.Core.Configuration;
using MvcEngine.Blog.Components.Attributes;
using MvcEngine.Mvc;
using MvcEngine.Mvc.Models;
using System.IO;
using MvcEngine.Core.Extensions;
using MvcEngine.Blog.Managers;
using MvcEngine.Core.Content;
using MvcEngine.Blog.Models;
using MvcEngine.Mvc.Controllers;
using MvcEngine.Core.Pagination;
using MvcEngine.Blog.Services;

namespace MvcEngine.Blog.BackOffice.Controllers
{
    public class BlogPostController : BaseController
    {
        #region Private fields

        private IBlogPostRepository postRepository = null;
        private IBlogTagRepository tagRepository = null;
        private IBlogCategoryRepository categoryRepository = null;
        private IBlogPostCommentRepository commentRepository = null;
        private IBlogPostNotifyRepository notifyRepository = null;

        #endregion

        #region Constructors

        public BlogPostController()
        {
            postRepository = IoC.Resolve<IBlogPostRepository>();
            tagRepository = IoC.Resolve<IBlogTagRepository>();
            categoryRepository = IoC.Resolve<IBlogCategoryRepository>();
            commentRepository = IoC.Resolve<IBlogPostCommentRepository>();
            notifyRepository = IoC.Resolve<IBlogPostNotifyRepository>();
        }

        #endregion

        public MvcEngineModel List(Guid blogId, int? pageNumber)
        {
            if (!pageNumber.HasValue)
                pageNumber = 1;
            if (pageNumber.Value <= 0)
                return new MvcEngineModel { ViewName = "InvalidPageRequest" };

            IPagination<BlogPost> pagination = BlogPostManager.Current.GetPosts(blogId, pageNumber.Value, 10);
            //if (pagination.TotalItems == 0)
            //    return new MvcEngineModel { ViewName = "Empty" };
            //if (pageNumber.Value > pagination.TotalPages)
              //  return new MvcEngineModel { ViewName = "InvalidPageRequest" };

            var blog = BlogManager.Current.GetBlog(blogId);

            BlogPostListPaginationViewModel model = new BlogPostListPaginationViewModel()
            {
                TotalItems = pagination.TotalItems,
                TotalPages = pagination.TotalPages,
                BlogName = blog.Name,
                Posts = new List<BlogPostDetailsViewModel>()
            };

            foreach (var post in pagination)
            {
                var postViewModel = new BlogPostDetailsViewModel()
                {
                    Id = post.Id,
                    Slug = post.Slug,
                    BlogId = post.BlogId,
                    Author = post.Author,
                    Comments = BlogPostManager.Current.GetComments(post.Id),
                    PostCategories = BlogCategoryManager.Current.GetAllByPost(post.Id),
                    PostTags = BlogPostTagManager.Current.GetAllByPost(post.Id),
                    Title = post.Title,
                    PublishedDate = post.PublishedDate
                };
                model.Posts.Add(postViewModel);
            }

            return model;
        }

        [AcceptVerbs(HttpVerbs.Post)]
        [ValidateInput(false)]
        [AntiForgeryValidationFilter]
        public MvcEngineModel UploadFile(Guid blogId, string blogName, string PostContent, HttpPostedFileBase file, Guid? postId)
        {
            if (file == null)
                throw new BusinessException("Uploaded file can't be null.");

            string directory = PrepareDirectory(blogId);
            string fileName = file.FileName.UrlEncode();
            string filePath = Path.Combine(directory, fileName);
            string fileExtension = Path.GetExtension(fileName).Remove(0, 1);
            if (!FileHelper.Current.Exists(filePath))
                file.SaveAs(filePath);

            ValueProviderResult content = ModelState["PostContent"].Value;
            ExtensionConfigurationElement element = ConfigurationUtil.Current.Extensions.GetElement(fileExtension);
            string value = null;

            var blog = BlogManager.Current.GetBlog(blogId);
            var page = ContentManager.Current.GetPage(blog.PageId);

            if (element == null || element.Type != "image")
            {
                string tag = "<p><a href=\"{0}\">{1}</a></p>";
                string text = fileName + " (" + FileHelper.Current.SizeFormat(file.ContentLength, "N") + ")";
                value = content.AttemptedValue + string.Format(tag, Url.PostFile(page.Name, DateTime.Now.Year, DateTime.Now.Month, fileName), text);
            }
            else
            {
                value = content.AttemptedValue + "<img src=\"" + Url.PostFile(page.Name, DateTime.Now.Year, DateTime.Now.Month, fileName) + "\" alt=\"" + file.FileName + "\"/>";
            }
            ModelState["PostContent"].Value = new ValueProviderResult(value, value, content.Culture);

            return Edit(blogId, blogName, postId);
        }

        [AcceptVerbs(HttpVerbs.Get)]
        public MvcEngineModel Edit(Guid blogId, string blogName, Guid? postId)
        {
            BlogPostEditViewModel model = null;
            if (postId.HasValue)
            {
                BlogPost post = BlogPostManager.Current.GetPost(postId.Value);
                if (post == null)
                    return new MvcEngineModelItem<Guid>() { Item = postId.Value, ViewName = "PostNotFound" };

                model = new BlogPostEditViewModel()
                {
                    Id = post.Id,
                    Author = post.Author,
                    BlogId = post.BlogId,
                    BlogName = blogName,
                    Description = post.Description,
                    IsCommentEnabled = post.IsCommentEnabled,
                    Keywords = post.Keywords,
                    PublishedDate = post.PublishedDate,
                    PostContent = post.PostContent,
                    Rating = post.Rating,
                    Slug = post.Slug,
                    Title = post.Title,
                    PostCategories = BlogCategoryManager.Current.GetAllByPost(post.Id),
                    PostTags = BlogPostTagManager.Current.GetAllByPost(post.Id),
                    Categories = BlogCategoryManager.Current.GetAll(blogId),
                    CommentCount = BlogPostManager.Current.GetComments(post.Id).Count,
                    Tags = BlogPostTagManager.Current.GetAll(blogId)
                };
            }
            else
            {
                model = new BlogPostEditViewModel()
                {
                    BlogId = blogId,
                    BlogName = blogName,
                    Categories = BlogCategoryManager.Current.GetAll(blogId),
                    Tags = BlogPostTagManager.Current.GetAll(blogId)
                };
            }
            model.ViewName = "Edit";
            return model;
        }

        [AcceptVerbs(HttpVerbs.Post)]
        [AntiForgeryValidationFilter]
        public ActionResult Delete(string blogName, Guid postId)
        {

            BlogPostManager.Current.DeletePost(postId);
            return Redirect(Url.Blog(blogName));
        }

        [AcceptVerbs(HttpVerbs.Post)]
        [ActionName("Edit")]
        [ValidateInput(false)]
        [AntiForgeryValidationFilter]
        public object Save(Guid? postId, BlogPost post, Guid blogId, string blogName, Dictionary<Guid, bool> categories, Dictionary<Guid, bool> tags)
        {
            if (ModelState.IsValid)
            {
                if (!postId.HasValue)
                {
                    post.Id = Guid.NewGuid();
                    post.BlogId = blogId;
                    post.CreatedDate = DateTime.Now;
                }
                else
                {
                    post.Id = postId.Value;
                    post.BlogId = blogId;
                }

                var postCategories = new List<BlogPostCategory>();
                if (categories != null)
                {
                    foreach (var item in categories.Where(c => c.Value))
                    {
                        BlogPostCategory category = IoC.Resolve<BlogPostCategory>();
                        category.CategoryId = item.Key;
                        category.Id = Guid.NewGuid();
                        category.PostId = post.Id;
                        postCategories.Add(category);
                    }
                }
                var postTags = new List<BlogPostTag>();
                if (tags != null)
                {
                    foreach (var item in tags.Where(c => c.Value))
                    {
                        BlogPostTag tag = IoC.Resolve<BlogPostTag>();
                        tag.TagId = item.Key;
                        tag.Id = Guid.NewGuid();
                        tag.PostId = post.Id;
                        postTags.Add(tag);
                    }
                }

                BlogPostManager.Current.SavePost(post, postCategories, postTags);

                if (postId.HasValue)
                {
                    return Json(new { model = "valid" });
                }
                else
                {
                    return Json(new { model = "redirect", redirectUrl = Url.EditPost(post.Id) });
                }
            }
            return Json(new { model = "invalid", errors = ModelState.GetErrors() });
        }

        #region Comment functionality

        [AcceptVerbs(HttpVerbs.Post)]
        [AntiForgeryValidationFilter]
        public RedirectResult DeleteComment(Guid blogId, string blogName, Guid postId, Guid commentId)
        {
            BlogPostManager.Current.DeleteComment(commentId);
            BlogPost post = BlogPostManager.Current.GetPost(postId);
            if (post == null)
            {
                return Redirect(Url.Blog(blogName));
            }
            return Redirect(Url.PostDetails(post.Slug, post.CreatedDate));
        }

#warning make it post
        [AcceptVerbs(HttpVerbs.Get)]
        public RedirectResult DeleteComment(string blogName, Guid commentId)
        {
            var blog = BlogManager.Current.GetBlog(blogName);
            var comment = BlogPostManager.Current.GetComment(commentId);
            if (comment != null)
            {
                BlogPostManager.Current.DeleteComment(commentId);
            }
            return Redirect(Url.Comments());
        }

        [AcceptVerbs(HttpVerbs.Get)]
        public MvcEngineModel Comments(string blogName)
        {
            var blog = BlogManager.Current.GetBlog(blogName);
            var comments = commentRepository.GetByBlog(blog.Id);

            var blogViewData = new BlogViewData<IList<BlogPostComment>>() { Blog = blog, Item = comments };

            return new MvcEngineModelItem<BlogViewData<IList<BlogPostComment>>>() { Item = blogViewData };
        }

        #endregion

        #region Protected methods

        protected virtual string PrepareDirectory(Guid blogId)
        {
            string year = DateTime.Now.Year.ToString();
            string month = DateTime.Now.Month.ToString();

            string directoryPath = ConfigurationUtil.Current.ModulesFolder + Path.DirectorySeparatorChar +
                this.HttpContext.Items["moduleName"].ToString() +
                Path.DirectorySeparatorChar + "Content" + Path.DirectorySeparatorChar + blogId.ToString() +
                Path.DirectorySeparatorChar + year + Path.DirectorySeparatorChar + month;

            DirectoryHelper.Current.CheckFolder(directoryPath);
            return directoryPath;
        }

        #endregion
    }
}
